use ggez::audio;
use ggez::audio::SoundSource;
use ggez::Context;
use std::collections::HashMap;
use hecs::World; 
use std::fmt;
use std::fmt::Display;
use std::time::Duration;

use crate::events::Event;

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct Position {
    pub x: u8,
    pub y: u8,
    pub z: u8,
}

pub struct Renderable {
    paths: Vec<String>,
}

pub enum RenderableKind {
    Static,
    Animated,
}

impl Renderable {
    pub fn new_static(path: &str) -> Self {
        Self {
            paths: vec![path.to_string()],
        }
    }

    pub fn new_animated(paths: Vec<&str>) -> Self {
        Self {
            paths: paths.iter().map(|p| p.to_string()).collect(),
        }
    }

    pub fn kind(&self) -> RenderableKind {
        match self.paths.len() {
            0 => panic!("invalid renderable"),
            1 => RenderableKind::Static,
            _ => RenderableKind::Animated,
        }
    }

    pub fn path(&self, path_index: usize) -> String {
        // If we get asked for a path that is larger than the
        // number of paths we actually have, we simply mod the index
        // with the length to get an index that is in range.
        self.paths[path_index % self.paths.len()].clone()
    }
}

pub struct Wall {}

pub struct Player {}

#[derive(PartialEq)]
pub enum BoxColour {
    Red,
    Blue,
}

impl Display for BoxColour {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(match self {
            BoxColour::Red => "red",
            BoxColour::Blue => "blue",
        })?;
        Ok(())
    }
}

pub struct Box {
    pub colour: BoxColour,
}

pub struct BoxSpot {
    pub colour: BoxColour,
}

pub struct Movable;

pub struct Immovable;

#[derive(Default, Copy, Clone, PartialEq)]
pub enum GameplayState {
    #[default]
    MainMenu,
    LevelSelect,
    DifficultySelect,
    Playing,
    Won,
    Return,
    Failed,
}

impl Display for GameplayState {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(match self {
            GameplayState::MainMenu => "Main Menu",
            GameplayState::LevelSelect => "Level Select",
            GameplayState::DifficultySelect => "Difficulty Select",
            GameplayState::Playing => "Playing",
            GameplayState::Won => "Won",
            GameplayState::Return => "Return",
            GameplayState::Failed => "Failed",
        })?;
        Ok(())
    }
}

#[derive(Default)]
pub struct Gameplay {
    pub state: GameplayState,
    pub moves_count: u32,
    pub max_moves: u32,  // 新增：最大步数限制
    pub difficulty: Difficulty,  // 新增：难度设置
}

impl Gameplay {
    // 根据关卡和难度获取最大步数
    pub fn get_max_moves_for_level_and_difficulty(level: usize, difficulty: Difficulty) -> u32 {
        match (level, difficulty) {
            (1, Difficulty::Easy) => 50,
            (1, Difficulty::Hard) => 30,
            (2, Difficulty::Easy) => 80,
            (2, Difficulty::Hard) => 50,
            (3, Difficulty::Easy) => 120,
            (3, Difficulty::Hard) => 80,
            _ => 50, // 默认值
        }
    }
}

#[derive(Default)]
pub struct Time {
    pub delta: Duration,
}

#[derive(Default)]
pub struct EventQueue {
    pub events: Vec<Event>,
}

#[derive(Default)]
pub struct AudioStore {
    pub sounds: HashMap<String, std::boxed::Box<audio::Source>>,
}

impl AudioStore {
    pub fn play_sound(&mut self, context: &mut Context, sound: &str) {
        if let Some(source) = self.sounds.get_mut(sound) {
            if source.play_detached(context).is_ok() {
                println!("Playing sound: {}", sound);
            }
        }
    }
}

// 新增菜单相关组件
pub struct MenuItem {
    pub text: String,
    pub action: MenuAction,
    pub is_selected: bool,
}

pub enum MenuAction {
    StartGame,
    QuitGame,
}

pub struct Menu {
    pub items: Vec<MenuItem>,
    pub selected_index: usize,
}

#[derive(Default, Copy, Clone, PartialEq)]
pub enum Difficulty {
    #[default]
    Easy,
    Hard,
}

impl Display for Difficulty {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(match self {
            Difficulty::Easy => "Easy",
            Difficulty::Hard => "Hard",
        })?;
        Ok(())
    }
}

